// Copyright 2011 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Classes used to support Message's in protorpc.
 * @author joetyson@gmail.com (Joe Tyson)
 */

goog.provide('abc');
goog.provide('protorpc.Service');


/**
 * Definition of a method in a service.
 *
 * @param {protorpc.MessageDefinition_} responseType The response type.
 * @param {protorpc.MessageDefinition_} requestType The request type.
 * @constructor
 */
protorpc.MethodDefinition_ = function(requestType, responseType) {
  this.name = null;
  this.requestType = requestType;
  this.responseType = responseType;
};

/**
 * Validates that the request type matches the methods definition.
 * @param {Object} request Request message.
 */
protorpc.MethodDefinition_.prototype.validateRequest = function(request) {
  throw Error('Not Implemented');
};

/**
 * Validates that the response type matches the methods definition.
 * @param {Object} response Response message.
 */
protorpc.MethodDefinition_.prototype.validateResponse = function(response) {
  throw Error('Not Implemented');
};


/**
 * Definition of a service.
 *
 * @param {string} name Service name.
 * @private
 * @constructor
 */
protorpc.ServiceDefinition_ = function(name) {
  this.name = name;
  this.methods = [];
};

/**
 * @return {Object.<*, function(protorpc.Message_, function(rpc))>}
 */
protorpc.ServiceDefinition_.prototype.createStub = function() {
  var stub = function() {};
  for (var i = 0; i < this.methods.length; i++) {
    var method = this.methods[i];
    stub.prototype[method.name] = goog.abstractMethod;
  }
  return stub;
};


/**
 * @param {string} name Service name.
 * @param {Object.<string, *>} options Service options.
 * @return {!Function} constructor
 * @export
 */
protorpc.Service = function(name, options) {
  var definition = new protorpc.ServiceDefinition_(name);

  /**
   * @type {Object.<string, protorpc.MethodDefinition_>}
   */
  var methods = options['methods'] || [];
  for (var methodName in methods) {
    var method = methods[methodName];
    method.name = methodName;
    definition.methods.push(method);
  };

  var stub = definition.createStub();

  /**
   * @param {protorpc.remote.Channel}
   */
  return function(channel) {
    return new stub();
  };
};


/**
 * @constructor
 * @private
 */
protorpc.Service_ = function(definition) {
  this.definition_ = definition;
};


/**
 * @param {!Function} requestType Request type factory.
 * @param {!Function} responseType Response type factory.
 * @export
 */
protorpc.Method = function(requestType, responseType) {
  return new protorpc.MethodDefinition_(requestType, responseType);
};